﻿//-----------------------------------------------------------------------
// <copyright file="MessageHelper.cs" company="AFS">
// Copyright (c) AFS. All rights reserved.
//
//    This file is part of Chatbox.
//
//    Chatbox is free software: you can redistribute it and/or modify
//    it under the terms of the GNU Lesser General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    any later version.
//
//    Chatbox is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//    GNU Lesser General Public License for more details.
//
//    You should have received a copy of the GNU Lesser General Public License
//    along with Chatbox. If not, see http://www.gnu.org/copyleft/lesser.html
// </copyright>
//----------------------------------------------------------------------- 

namespace ChatBox.DomainObjects.XmlFeedObjects
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Xml.Linq;

    using ChatBox.DomainObjects.MessageTypes;
    using ChatBox.DomainObjects.ResultData;
    using ChatBox.Utility;

    /// <summary>
    /// Helper methods on Message
    /// </summary>
    public static class MessageHelper
    {
        /// <summary>
        /// read messages from an xml document
        /// </summary>
        /// <param name="doc">the xml document</param>
        /// <param name="isPublic">Are the messages to be flagged as public</param>
        /// <returns>the contructed object list</returns>
        public static ChatDataResult ToMessages(this XContainer doc, bool isPublic)
        {
            ChatDataResult result = new ChatDataResult(true, string.Empty);

            var messages = doc.Elements("messages");
            var roomElement = messages.Elements("room").FirstOrDefault();

            if (roomElement != null)
            {
                result.Room = new Link
                    {
                        NodeId = roomElement.Attribute("room_id").Value.ToInteger(),
                        Text = roomElement.Value
                    };
            }

            var topicElement = messages.Elements("topic").FirstOrDefault();
            if (topicElement != null)
            {
                result.Topic = topicElement.Value;
            }

            var msgList = messages.Elements("msglist").Elements("msg");
            var messageQuery =
                from msg in msgList
                select new Message
                    {
                        Id = msg.Attribute("msg_id").Value.ToInteger(),
                        Sent = msg.Attribute("msg_time").Value.ToDateTime(),
                        RawMessageText = msg.Element("txt").Value,
                        From = msg.Element("from").Element("e2link").ToLink(),
                        Group = msg.Element("grp") == null ? null : msg.Element("grp").Element("e2link").ToGroupLink(),
                        IsPublic = isPublic
                    };

            List<Message> messagesList = messageQuery.ToList();
            messagesList.Sort((m1, m2) => m1.Id - m2.Id);
            result.Messages = messagesList;

            if (result.Messages.HasItems())
            {
                MessageTypeDetection messageTyper = new MessageTypeDetection();

                foreach (Message message in result.Messages)
                {
                    messageTyper.SetMessageTextType(message);
                }
            }

            return result;
        }

        /// <summary>
        /// Find the largest Id in the messages
        /// </summary>
        /// <param name="messages">the messages to look through</param>
        /// <returns>the largest id</returns>
        public static int MaxMessageId(this IEnumerable<Message> messages)
        {
            int result = 0;
            foreach (Message message in messages)
            {
                if (message.Id > result)
                {
                    result = message.Id;
                }
            }

            return result;
        }

        /// <summary>
        /// Merge new messages into the list
        /// </summary>
        /// <param name="messages">the target list</param>
        /// <param name="newMessages">the messages to add</param>
        public static void AddNewMessages(this IList<Message> messages, IEnumerable<Message> newMessages)
        {
            int maxId = messages.MaxMessageId();

            foreach (Message message in newMessages)
            {
                if (message.Id > maxId)
                {
                    messages.Add(message);
                }
            }
        }

        /// <summary>
        /// Discard old messages that make the list larger then the max
        /// </summary>
        /// <param name="messages">the messages to process</param>
        /// <param name="max">the maximum count</param>
        public static void RemoveExcessMessages(this IList<Message> messages, int max)
        {
            while (messages.Count > max)
            {
                messages.RemoveAt(0);
            }
        }

        /// <summary>
        /// Get all unique groups in the message list
        /// </summary>
        /// <param name="messages">the messages to process</param>
        /// <returns>the list of groups</returns>
        public static IList<Link> ListGroups(this IList<Message> messages)
        {
            List<Link> result = new List<Link>();

            foreach (var message in messages)
            {
                if ((message.Group != null) && 
                    (message.Group.GroupType == GroupType.UserGroup) && 
                    (!result.Contains(message.Group)))
                {
                    result.Add(message.Group);
                }
            }

            return result;
        }

        /// <summary>
        /// Get all unique senders in the message list
        /// </summary>
        /// <param name="messages">the messages to process</param>
        /// <returns>the list of senders</returns>
        public static IList<Link> ListFrom(this IList<Message> messages)
        {
            List<Link> result = new List<Link>();

            foreach (var message in messages)
            {
                if ((message.From != null) && (!result.Contains(message.From)))
                {
                    result.Add(message.From);
                }
            }

            return result;
        }

        /// <summary>
        /// Get all unique senders in the message list
        /// </summary>
        /// <param name="messages">the messages to process</param>
        /// <returns>the list of senders</returns>
        public static IList<int> MessageIds(this IEnumerable<Message> messages)
        {
            List<int> result = new List<int>();

            foreach (var message in messages)
            {
                result.Add(message.Id);
            }

            return result;
        }
    }
}
